package com.ebupt.migu.music.api.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.ebupt.migu.music.api.entity.Activity;
import com.ebupt.migu.music.api.entity.CMSNoticeRequest;
import com.ebupt.migu.music.api.entity.CMSNoticeResponse;
import com.ebupt.migu.music.api.entity.CmsUpdateNotice;
import com.ebupt.migu.music.api.mapper.CMSNoticeMapper;
import com.ebupt.migu.music.api.service.CMSNoticeService;
import com.ebupt.migu.music.common.api.CatalogResponse;
import com.ebupt.migu.music.common.api.ContentDetail;
import com.ebupt.migu.music.common.api.RestResponse;
import com.ebupt.migu.music.common.exception.MiguRuntimeException;
import com.ebupt.migu.music.common.exception.MyException;
import com.ebupt.migu.music.common.exception.StatusEnum;
import com.ebupt.migu.music.common.util.DateUtil;
import com.ebupt.migu.music.common.util.HttpUtils;
import com.ebupt.migu.music.common.util.HttpsUtils;
import com.ebupt.migu.music.common.util.JsonUtils;
import com.ebupt.migu.music.outside.mapper.CMSMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by Intellij IDEA.
 * User:  liuyangyang@cd.ebupt.com
 * Date:  2019/10/18
 */
@Slf4j
@Service
public class CMSNoticeServiceImpl implements CMSNoticeService {

    @Value("${cms.pid}")
    private String CMS_PID;
    @Value("${cms.key}")
    private String CMS_KEY;
    @Value("${cms.extranet}")
    private String CMS_EXTRANET;
    @Value("${cms.marketing}")
    private String CMS_MARKETING;
    @Value("${cms.content}")
    private String CMS_CONTENT;
    @Value("${cms.channel}")
    private String CMS_CHANNEL;
    @Value("${cms.platform}")
    private String CMS_PLATFORM;

    /**
     * 未回调
     * cms_update_notice
     * callback = 0
     */
    public static final byte NOTRUN = 0;

    /**
     * 已经回调
     * cms_update_notice
     * callback = 1
     */
    public static final byte RUN = 1;

    @Autowired
    private CMSNoticeMapper cmsNoticeMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CMSMapper cmsMapper;


    private Map<Integer, String> channels = new HashMap<>();
    private Map<Integer, String> platforms = new HashMap<>();

    /**
     * cms通知商户更新活动列表
     *
     * @param cmsNoticeRequest
     * @return
     */
    @Override
    public CMSNoticeResponse updateNotice(CMSNoticeRequest cmsNoticeRequest) {
        CMSNoticeResponse cmsNoticeResponse = new CMSNoticeResponse();
        if (null == cmsNoticeRequest) {
            log.info("cmsNoticeRequest实例为空");
            cmsNoticeResponse.setNoticeStatus("0000001");
            cmsNoticeResponse.setNoticeMessage("参数为空");
            log.info("CMS通知活动更新，返回结果{}", cmsNoticeResponse.toString());
            return cmsNoticeResponse;
        }
        if (StringUtils.isBlank(cmsNoticeRequest.getStartQueryId())) {
            log.info("startQueryId参数为空");
            cmsNoticeResponse.setNoticeStatus("0000001");
            cmsNoticeResponse.setNoticeMessage("startQueryId参数为空");
            log.info("CMS通知活动更新，返回结果{}", cmsNoticeResponse.toString());
            return cmsNoticeResponse;
        }
        // 获取startQueryId的时间，格式：年月日
        String startQueryId = cmsNoticeRequest.getStartQueryId().substring(0, 8);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        long days;
        try {
            // 获取startQueryId的毫秒值
            long queryTime = simpleDateFormat.parse(startQueryId).getTime();
            log.info("startQueryId的毫秒值为：{}", queryTime);
            // 获取当前时间的毫秒值
            long nowTime = System.currentTimeMillis();
            days = Math.abs((nowTime - queryTime) / (1000 * 60 * 60 * 24));
        } catch (ParseException e) {
            throw new MyException(StatusEnum.BUSINID, "时间解析异常");
        }
        if (days > 90L) {
            log.info("时间差已经超过3个月，当前天数时间差为：{}", days);
            cmsNoticeResponse.setNoticeStatus("0000001");
            cmsNoticeResponse.setNoticeMessage("当前数据太久远，不需调用");
            log.info("CMS通知活动更新，返回结果{}", cmsNoticeResponse);
            return cmsNoticeResponse;
        }
        if (StringUtils.isBlank(cmsNoticeRequest.getUpdateInterfaces())) {
            log.info("updateInterfaces参数为空，不需要回调");
            cmsNoticeResponse.setNoticeStatus("000000");
            cmsNoticeResponse.setNoticeMessage("调用成功");
            log.info("CMS通知活动更新，返回结果{}", cmsNoticeResponse.toString());
            return cmsNoticeResponse;
        }
        if (!cmsNoticeRequest.getUpdateInterfaces().contains("columncontent") && !cmsNoticeRequest.getUpdateInterfaces().contains("marketing")) {
            log.info("updateInterfaces参数内不含指定内容通知（marketing/columncontent），不需要回调");
            cmsNoticeResponse.setNoticeStatus("000000");
            cmsNoticeResponse.setNoticeMessage("调用成功");
            log.info("updateInterfaces参数内不含指定内容通知（marketing/columncontent），不需要回调");
            return cmsNoticeResponse;
        }
        CmsUpdateNotice cmsUpdateNotice = new CmsUpdateNotice();
        cmsUpdateNotice.setStartQueryId(cmsNoticeRequest.getStartQueryId());
        cmsUpdateNotice.setUpdateInterfaces(cmsNoticeRequest.getUpdateInterfaces());
        cmsUpdateNotice.setCallback(NOTRUN);
        try {
            // 添加记录
            cmsNoticeMapper.updateNotice(cmsUpdateNotice);
        } catch (Exception e) {
            log.error("接口异常{}", e);
        }
        cmsNoticeResponse.setNoticeStatus("000000");
        cmsNoticeResponse.setNoticeMessage("调用成功");
        log.info("CMS通知活动更新，返回结果{}", cmsNoticeResponse.toString());
        //executeTask(cmsUpdateNotice);
        return cmsNoticeResponse;
    }

    /**
     * 执行定时任务获取最新活动列表
     */
    @Override
    public void doService() {
        // 查询所有未回调的活动更新
        List<CmsUpdateNotice> cmsUpdateNotices = cmsNoticeMapper.notRuns();
        if (CollectionUtils.isEmpty(cmsUpdateNotices)) {
            log.info("所有活动更新均已经回调，当前无待执行");
            return;
        }
        // 执行任务
        for (CmsUpdateNotice cmsUpdateNotice : cmsUpdateNotices) {
            doTask(cmsUpdateNotice);
           /* log.info("异步调用开始");
            autoTouchOffService.updateNotice(cmsUpdateNotice.getStartQueryId());*/
        }
        log.info("获取cms活动列表任务完成");
    }

    /**
     * 分两步执行
     *
     * @param cmsUpdateNotice
     */
    private void doTask(final CmsUpdateNotice cmsUpdateNotice) {
        this.executeTask(cmsUpdateNotice);
        this.update(cmsUpdateNotice);
    }

    public void executeTask(CmsUpdateNotice cmsUpdateNotice) {
        // 栏目集合
        Map<Integer, Integer> map = new HashMap<>();
        Map<String, Object> paramsMap = this.getCatalogRequestMap(cmsUpdateNotice);
        List<Integer> deleteList = new ArrayList<>();
        List<Integer> onlineList = new ArrayList<>();
        boolean needPage = true;
        while (needPage) {
            log.info("调用栏目内容接口, cmsUpdateNotice:{}, catalogRequest:{} ", cmsUpdateNotice.toString(), paramsMap.toString());
            String result = null;
            try {
                result = HttpUtils.doGetRequest(CMS_EXTRANET + CMS_CONTENT, paramsMap);
            } catch (Exception e) {
                log.error("调用栏目内容接口数据失败", e);
                throw new MiguRuntimeException("调用栏目内容接口数据失败", e);
            }
            log.info("栏目内容返回", result);
            CatalogResponse catalogResponse = JsonUtils.json2Obj(result, CatalogResponse.class);
            log.info("catalogResponse：{}", catalogResponse.toString());
            if (!"000000".equals(catalogResponse.getState())) {
                log.error("获取栏目内容接口数据失败");
                throw new MiguRuntimeException("获取栏目内容接口数据失败: " + catalogResponse.getMessage());
            }
            List<ContentDetail> list = catalogResponse.getContent().getList();
            if (null == list || list.isEmpty()) {
                log.error("获取栏目内容接口数据失败");
                break;
            }
            for (ContentDetail contentDetail : list) {
                if (catalogs.contains(contentDetail.getColumnId())) {
                    // 上线和待上线都入库
                    // if (contentDetail.getRelationStatus() == 1 || contentDetail.getRelationStatus() == 2) {
                    // 1-上线 2-待上线 2019-12-05
                    if (contentDetail.getRelationStatus() == 2) {
                        map.put(contentDetail.getContentId(), contentDetail.getColumnId());
                        onlineList.add(contentDetail.getContentId());
                    } else {
                        deleteList.add(contentDetail.getContentId());
                    }
                }
            }
            boolean isEnd = catalogResponse.getContent().isEnd();
            String lastChangeId = catalogResponse.getContent().getLastChangeId();
            if (isEnd) {
                needPage = false;
            }
            paramsMap.put("startQueryId", lastChangeId);
        }
        log.info("符合条件的在线或待入库栏目数据:{}, 共有:{}条", onlineList, onlineList.size());
        //
        Map<String, Object> marketMapPara = this.getMarketRequestMap(cmsUpdateNotice);
        if (CollectionUtils.isNotEmpty(onlineList)) {
            needPage = true;
            while (needPage) {
                // 4.25.IF1-25：门户查询统一CMS营销实体的接口
                log.info("调用营销实体接口, catalogRequest:{}", marketMapPara.toString());
                String marketJSON = null;
                try {
                    marketJSON = HttpUtils.doGetRequest(CMS_EXTRANET + CMS_MARKETING, marketMapPara);
                } catch (Exception e) {
                    log.error("调用营销接口失败", e);
                    throw new MiguRuntimeException("调用营销接口失败", e);
                }
                log.info("营销实体返回:{}", marketJSON);
                Map marketMap = JsonUtils.json2Obj(marketJSON, Map.class);
                if (!"000000".equals(marketMap.get("state"))) {
                    log.error("获取营销实体接口数据失败");
                    throw new MiguRuntimeException("获取营销实体接口数据失败" + marketMap.get("message"));
                }
                Map contentMap = (Map) marketMap.get("content");
                JSONArray contentList = (JSONArray) contentMap.get("list");
                if (contentList == null || contentList.isEmpty()) {
                    log.error("获取营销实体接口数据为空");
                    break;
                }
                for (Object object : contentList) {
                    Map market = (Map) object;
                    Integer marketingId = (Integer) market.get("marketingId");
                    log.info("marketing id:{}", marketingId);
                    if (!onlineList.contains(marketingId)) {
                        log.info("{}不在在线列表中", marketingId);
                        continue;
                    }
                    Activity activity = new Activity();
                    activity.setActivityId(String.valueOf(marketingId));
                    activity.setActivityName((String) market.get("marketingName"));
                    activity.setPosition(position.get(map.get(marketingId)));
                    log.info("position:{}, marketing id:{}", position.get(map.get(marketingId)), marketingId);
                    activity.setContentId(String.valueOf(market.get("marketingContentId")));
                    activity.setTypeId(String.valueOf(market.get("marketingType")));
                    activity.setTypeName(types.get(String.valueOf(market.get("marketingType"))));
                    activity.setUrl(String.valueOf(market.get("productId")));
                    activity.setVersion(version.get(map.get(marketingId)));

                    StringBuilder cityAll = new StringBuilder();
                    JSONArray cityArrays = (JSONArray) market.get("cities");
                    if (cityArrays != null && !cityArrays.isEmpty()) {
                        for (Object cityArray : cityArrays) {
                            Map city = (Map) cityArray;
                            String cityName = (String) city.get("cityName");
                            cityAll.append(cityName).append(",");
                        }
                        String cityStr = cityAll.toString();
                        cityStr = cityStr.substring(0, cityStr.lastIndexOf(","));
                        activity.setCity(cityStr);
                    }

                    JSONArray provinceArrays = (JSONArray) market.get("provinces");
                    StringBuilder provinceAll = new StringBuilder();
                    if (provinceArrays != null && !provinceArrays.isEmpty()) {
                        for (Object provinceArray : provinceArrays) {
                            Map province = (Map) provinceArray;
                            String provinceName = (String) province.get("provinceName");
                            provinceAll.append(provinceName).append(",");
                        }
                        String provinceStr = provinceAll.toString();
                        provinceStr = provinceStr.substring(0, provinceStr.lastIndexOf(","));
                        activity.setProvince(provinceStr);
                    }

                    JSONArray channelsArrays = (JSONArray) market.get("channels");
                    if (channelsArrays != null && !channelsArrays.isEmpty()) {
                        StringBuilder channelsAll = new StringBuilder();
                        for (Object channelsArray : channelsArrays) {
                            Map channels = (Map) channelsArray;
                            Integer channelId = (Integer) channels.get("channelId");
                            String channelName = this.getChannelName(channelId);
                            channelsAll.append(channelName).append(",");
                        }
                        String channelStr = channelsAll.toString();
                        channelStr = channelStr.substring(0, channelStr.lastIndexOf(","));
                        activity.setChannel(channelStr);
                    }

                    JSONArray platformsArrays = (JSONArray) market.get("platforms");
                    if (platformsArrays != null && !platformsArrays.isEmpty()) {
                        StringBuilder platformsAll = new StringBuilder();
                        for (Object platformsArray : platformsArrays) {
                            Map platforms = (Map) platformsArray;
                            Integer platformId = (Integer) platforms.get("platformId");
                            String platformName = this.getPlatformName(platformId);
                            platformsAll.append(platformName).append(",");
                        }
                        String platformStr = platformsAll.toString();
                        platformStr = platformStr.substring(0, platformStr.lastIndexOf(","));
                        activity.setPlatform(platformStr);
                    }
                    log.info("入库活动数据为:{}", activity.toString());
                    try {
                        cmsMapper.deleteByActivityID(activity.getActivityId());
                        cmsMapper.createActivity(activity);
                    } catch (Exception e) {
                        log.error("操作数据库失败", e);
                        throw new MiguRuntimeException("操作数据库失败");
                    }
                }
                boolean isEnd = (Boolean) contentMap.get("isEnd");
                String lastChangeId = (String) contentMap.get("lastChangeId");
                if (isEnd) {
                    needPage = false;
                }
                marketMapPara.put("startQueryId", lastChangeId);
            }
        }

        // 删除非在线的
        log.info("待删除数据数量:{}", deleteList.size());
        if (!deleteList.isEmpty()) {
            for (Integer activityId : deleteList) {
                log.info("删除活动:{}", activityId);
                cmsMapper.deleteByActivityID(activityId.toString());
            }
        }
    }

    /**
     * 更新已经运行标识位
     *
     * @param cmsUpdateNotice
     */
    public void update(CmsUpdateNotice cmsUpdateNotice) {
        CmsUpdateNotice record = new CmsUpdateNotice();
        record.setCallback(RUN);
        record.setId(cmsUpdateNotice.getId());
        cmsNoticeMapper.update(record);
    }

    private String getChannelName(int channelId) {
        String channelName = "";
        channelName = channels.get(channelId);
        return channelName;
    }

    private String getPlatformName(int platformId) {
        String platformName = "";
        platformName = platforms.get(platformId);
        return platformName;
    }

    private Map<String, Object> getMarketRequestMap(CmsUpdateNotice cmsUpdateNotice) {
        Map<String, Object> map = new HashMap<>();
        map.put("startQueryId", cmsUpdateNotice.getStartQueryId());
        map.put("PID", CMS_PID);
        Long sequentId = this.incr();
        String SEQ = CMS_PID + DateUtil.parseDateToStr(new Date(), DateUtil.DATE_TIME_FORMAT_YYYYMMDDHHMISS) + String.format("%08d", sequentId);
        String KEY = DigestUtils.md5Hex(SEQ + CMS_KEY);
        map.put("SEQ", SEQ);
        map.put("KEY", KEY);
        return map;
    }

    private Map<String, Object> getCatalogRequestMap(CmsUpdateNotice cmsUpdateNotice) {
        Map<String, Object> map = new HashMap<>();
        map.put("startQueryId", cmsUpdateNotice.getStartQueryId());
        map.put("PID", CMS_PID);
        Long sequentId = this.incr();
        String SEQ = CMS_PID + DateUtil.parseDateToStr(new Date(), DateUtil.DATE_TIME_FORMAT_YYYYMMDDHHMISS) + String.format("%08d", sequentId);
        String KEY = DigestUtils.md5Hex(SEQ + CMS_KEY);
        map.put("SEQ", SEQ);
        map.put("KEY", KEY);
        StringBuilder columnIds = new StringBuilder();
        for (Integer catalog : catalogs) {
            columnIds.append(String.valueOf(catalog)).append(",");
        }
        String columns = columnIds.toString();
        map.put("columnIds", columnIds.substring(0, columns.lastIndexOf(",")));
        return map;
    }

    private void getAllChannelAndPlatform() {
        Map<String, Object> map = new HashMap<>();
        map.put("startQueryId", "20130417121229945000|00000000000");
        map.put("PID", CMS_PID);
        Long sequentId = this.incr();
        String SEQ = CMS_PID + DateUtil.parseDateToStr(new Date(), DateUtil.DATE_TIME_FORMAT_YYYYMMDDHHMISS) + String.format("%08d", sequentId);
        String KEY = DigestUtils.md5Hex(SEQ + CMS_KEY);
        map.put("SEQ", SEQ);
        map.put("KEY", KEY);
        try {
            boolean needPage = true;
            while (needPage) {
                log.info("获取渠道信息: ", map.toString());
                String channelJSON = HttpUtils.doGetRequest(CMS_EXTRANET + CMS_CHANNEL, map);
                log.info("返回渠道信息： " + channelJSON);
                RestResponse<String> result = JsonUtils.json2Obj(channelJSON, RestResponse.class);
                String data = result.getData();
                Map channelMap = JsonUtils.json2Obj(data, Map.class);
                Map channelEntitys = (Map) channelMap.get("content");
                JSONArray channelListMap = (JSONArray) channelEntitys.get("list");
                if (channelListMap != null && !channelListMap.isEmpty()) {
                    for (Object channelList : channelListMap) {
                        Map channel = (Map) channelList;
                        channels.put((Integer) channel.get("channelId"), (String) channel.get("channelTitle"));
                    }
                }
                boolean isEnd = (Boolean) channelEntitys.get("isEnd");
                String lastChangeId = (String) channelEntitys.get("lastChangeId");
                if (isEnd) {
                    needPage = false;
                }
                map.put("startQueryId", lastChangeId);
            }
        } catch (Exception e) {
            log.error("获取渠道名称出错", e);
        }

        try {
            boolean needPage = true;
            map.put("startQueryId", "20130417121229945000|00000000000");
            while (needPage) {
                log.info("获取平台信息： ", map.toString());
                String platformJSON = HttpUtils.doGetRequest(CMS_EXTRANET + CMS_PLATFORM, map);
                log.info("返回平台信息： ", platformJSON);
                RestResponse<String> result = JsonUtils.json2Obj(platformJSON, RestResponse.class);
                String data = result.getData();
                Map platformMap = JsonUtils.json2Obj(data, Map.class);
                Map contentMap = (Map) platformMap.get("content");
                JSONArray list = (JSONArray) contentMap.get("list");
                if (list != null && !list.isEmpty()) {
                    for (Object platformEntity : list) {
                        Map platform = (Map) platformEntity;
                        platforms.put((Integer) platform.get("platformId"), (String) platform.get("platformName"));
                    }
                }
                boolean isEnd = (Boolean) contentMap.get("isEnd");
                String lastChangeId = (String) contentMap.get("lastChangeId");
                if (isEnd) {
                    needPage = false;
                }
                map.put("startQueryId", lastChangeId);
            }
        } catch (Exception e) {
            log.error("获取平台信息出错： ", e);
        }
    }

    /**
     * 原子自增
     *
     * @return
     */
    private Long incr() {
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        RedisAtomicLong redisAtomicLong = new RedisAtomicLong("cmsincr", redisTemplate.getConnectionFactory());
        Long cmsincr = redisAtomicLong.getAndIncrement();
        //  当计数到99999999时归零
        if (cmsincr == 999999999) {
            operations.set("cmsincr", 0);
            cmsincr = redisAtomicLong.getAndIncrement();
        }
        return cmsincr;
    }

    /**
     * 点位
     * 365935   - 首页Banner 【停止更新】
     * 4557177  - 音乐之声 【停止更新】
     * 15044649 - 音乐之声 【停止更新】
     * 21831737 - 音乐之声 【停止更新】
     * 31417432 - 音乐之声 2020-10-19
     * 15030373 - 首页Banner【停止更新】
     * 31417313 - 首页Banner 2020-11-05
     */
    private List<Integer> catalogs = Arrays.asList(31417432, 31417313);

    /**
     * 活动类型
     */
    private static Map<Integer, String> types = new HashMap<Integer, String>() {{
        put(1001, "活动栏目");
        put(1003, "专题栏目");
        put(1020, "歌单栏目（随身听）");
        put(1025, "歌单栏目（咪咕2.0）");
        put(1016, "MV栏目");
        put(1004, "MV歌曲");
        put(1301, "专辑");
        put(1302, "单曲");
        put(2019, "数字专辑");
        put(2028, "咪咕出品");
        put(2031, "票务对象");
        put(2009, "榜单");
        put(2100, "咪咕出品音频");
        put(2101, "咪咕出品视频");
        put(2102, "咪咕出品音频专辑");
        put(2103, "咪咕出品视频专辑");
        put(2002, "歌手");
        put(2104, "演唱会详情页（包括预告、直播、回放）");
        put(2105, "票务详情页面");
        put(2106, "彩铃专辑");
        put(2107, "彩铃歌单");
        put(2108, "DIY彩铃专辑");
        put(2109, "DIY彩铃歌单");
        put(2110, "贡献榜");
        put(2111, "MIGU Radio");
        put(2142, "短视频");
        put(2144, "视频彩铃");
        put(2145, "K歌活动");
        put(2146, "K歌主题");
        put(2147, "视讯导流链接");
    }};

    /**
     * 点位
     */
    private Map<Integer, String> position = new HashMap<Integer, String>() {{
        put(31417313, "首页Banner");
        put(31417432, "音乐之声（新）");
    }};

    /**
     * 点位版本号
     */
    private Map<Integer, String> version = new HashMap<Integer, String>() {{
        put(31417313, "7.0");
        put(31417432, "7.0");
    }};

    public static void main(String[] args) {
       String updateInterfaces="marketing";
        System.out.println(updateInterfaces.contains("marketing"));
    }
}
